package cn.persistenceCollection

import cn.persistenceCollection.fileBasedImpl.*
import com.easy.server.persistenceCollection.FileMapperType
import com.easy.server.persistenceCollection.FilePersistenceCollection
import java.nio.file.Path
import java.util.concurrent.*


/**
 * 一个用于管理所有持久化集合的上下文，用来控制如刷盘，设置等工作
 */
class PersistenceContext(var baseUrl: String = ".") : AutoCloseable {

    var flushPerOption = false //是否每个操作都及时刷盘
    var flushIntervalMills: Long = 1000 //当flushPerOption=false时 定时刷盘的间隔

    var defaultFileMapperType: FileMapperType = FileMapperType.MergedMemoryMapMapper//默认使用的FileMapper

    /**
     * map中value字节数量的冗余倍率。
     * 创建数据块时会为value分配额外的空间以便将来新的value进行替换
     * 如果冗余替换成功，则在插入新的键值对时不需要重新分配额外的空间，可以避免文件大小迅速膨胀
     * 0.5f意味着会为value分配1.5倍大小的空间
     *
     * 设置为负数则动态调整倍率
     */
    var mapOrSetValueRedundancyBytesRatio: Float = -1f
    private val fileFlusher: ScheduledExecutorService = Executors.newScheduledThreadPool(1);

    private val collections: MutableMap<FilePersistenceCollection, ScheduledFuture<*>?> = mutableMapOf()

    companion object {
        val default: PersistenceContext = PersistenceContext()
    }



    /**
     *
     * 给上下文注册一个持久化集合，如果没启用flushPerOption，则通过fileFlusher执行定时刷盘。
     * 主要目的是通过ScheduledExecutorService 进行定时数据刷盘操作。
     * 通过PersistenceContext.openXXX()创建的持久化集合无需手动register
     */
    @Synchronized
    fun register(collection: FilePersistenceCollection) {

        if (collection is AbstractFilePersistenceCollection) {
            if (!collection.flushPerOption) {
                val future = fileFlusher.scheduleAtFixedRate({
                    if (!collection.closed()) {
                        collection.flush()
                    }
                }, collection.flushIntervalMills, collection.flushIntervalMills, TimeUnit.MILLISECONDS)
                future.cancel(false)
                collections[collection] = future

            } else {
                collections[collection] = null
            }
        }

    }

    /**
     *
     * 从上下文中移除一个持久化集合
     * 这个方法无需手动调用。
     */
    @Synchronized
    fun unregister(collection: FilePersistenceCollection) {
        val scheduledFuture = collections.remove(collection)
        scheduledFuture?.cancel(false)
    }

    /**
     * 根据指定的name  获取一个FilePersistenceArrayList
     * 如果不存在，则创建一个新的，如果已存在，则会读取文件 获取原先的数据。
     */
    @Synchronized
    fun <T> openArrayList(
        name: String,
        serializer: Serializer<T>,
        initCap: Int = 16,

        ): FilePersistenceArrayList<T> {
        return FilePersistenceArrayList(
            getName(name),
            serializer,
            initCap,
            defaultFileMapperType,
            flushPerOption,
            flushIntervalMills,
            this
        )
    }

    fun <K, V> openMap(
        name: String,
        keySerializer: Serializer<K>,
        valueSerializer: Serializer<V>,
        initCap: Int = 16,

        ): FilePersistenceMap<K, V> {
        return FilePersistenceMap(
            getName(name),
            keySerializer,
            valueSerializer,
            initCap,
            mapOrSetValueRedundancyBytesRatio,
            defaultFileMapperType,
            flushPerOption,
            flushIntervalMills,
            this
        )
    }

    fun <E> openSet(
        name: String,
        serializer: Serializer<E>,
        initCap: Int = 16,

        ): FilePersistenceSet<E> {
        return FilePersistenceSet(
            getName(name),
            serializer,
            initCap,
            defaultFileMapperType,
            flushPerOption,
            flushIntervalMills,
            this
        )
    }

    private fun getName(name: String): String {
        return Path.of(baseUrl, name).toString()
    }

    @Synchronized
    override fun close() {
        collections.keys.forEach { it.close() }
        fileFlusher.shutdown()
        fileFlusher.awaitTermination(10, TimeUnit.SECONDS)

    }
}